package yang.yu.sunny.application.impl;

import org.dayatang.domain.EntityRepository;
import yang.yu.sunny.EventBus;
import yang.yu.sunny.application.ProductSalesVolume;
import yang.yu.sunny.application.SunnyApplication;
import yang.yu.sunny.domain.*;

import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.reducing;
import static java.util.stream.Collectors.toList;

/**
 * Created by yyang on 16/3/24.
 */
public class SunnyApplicationImpl implements SunnyApplication {

    private EntityRepository repository;

    public SunnyApplicationImpl(EntityRepository repository) {
        this.repository = repository;
    }

    @Override
    public void changeProductCategoryName(Long categoryId, String newName) {
        ProductCategory category = ProductCategory.get(categoryId);
        category.changeName(newName);
    }

    @Override
    public void changeProductName(Long productId, String newName) {
        Product product = Product.get(productId).orElseThrow(EntityNotFoundException::new);
        product.changeName(newName);
    }

    @Override
    public void changeCustomerName(Long customerId, String newName) {
        Customer customer = Customer.get(customerId).orElseThrow(EntityNotFoundException::new);
        customer.changeName(newName);
    }

    @Override
    public List<Order> findOrdersContains(Product product) {
        return repository.findByProperty(OrderItem.class, "product", product).stream()
                .map(OrderItem::getOrder)
                .sorted(Comparator.comparing(Order::getCreated))
                .collect(Collectors.toList());
    }

    @Override
    public List<ProductSalesVolume> findTopNBestSeller(TimeRange timeRange, long n) {
        List<OrderItem> items = repository.createJpqlQuery("select o from OrderItem o where o.order.created between :fromDate and :toDate")
                .addParameter("fromDate", timeRange.getFrom())
                .addParameter("toDate", timeRange.getTo())
                .list();
        Map<Product, Double> sales = items.stream()
                .collect(groupingBy(OrderItem::getProduct,
                        reducing(0.0, OrderItem::getTotalPrice, Double::sum)));
        return sales.keySet().stream().map(product -> new ProductSalesVolume(product, sales.get(product)))
                .sorted(Comparator.comparing(ProductSalesVolume::getAmount).reversed())
                .limit(n)
                .collect(toList());
    }
}
